package ui;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.ConnectException;
import java.rmi.NotBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.List;

import dot.Dot;

import p2p.Config;
import p2p.FileList;
import p2p.Kwalker;
import p2p.NeighborList;
import p2p.Peer;
import p2p.PeerPool;
import server.Message;
import server.RMIServer;

public class Terminal {
	public void runTerminal(RMIServer s, p2p.Peer thisPeer, PeerPool peerPool, NeighborList neighborList, FileList fileList, Kwalker k) throws IOException{
		String curLine = ""; // Line read from standard in
		boolean running = true;

		System.out.println("Enter a command (type 'quit' to exit or 'help' for help): ");
		InputStreamReader converter = new InputStreamReader(System.in);
		BufferedReader in = new BufferedReader(converter);

		while(running) {
			curLine = in.readLine();
			// HACK, when running the Script, in.readLine() will always be null
			if(curLine == null) return;
			String[] args = curLine.split(" ");

			if(curLine.equals("help")) { //help
				//hello [ip:port]
				System.out.println("hello [ip:port] : initiates discovery of other peers, possibly bootstrapping with the peer residing at ip:port.\n");
				//plist
				System.out.println("plist : lists the pool of peers known to the local peer. Your peer info should include the maximum number of neighbours that peer can have.\n");
				//nlist
				System.out.println("nlist : Lists the local peer's current neighbours. The peer info should include the maximum number of neighbours.\n");
				//nlist [peers] [-o output.dot]
				System.out.println("nlist [peers] [-o output.dot] : Iterates through the provided list of peers, retrieves each peer's neighbours, and generates a graph in the Graphviz dot format. If no arguments are given, only the local peer is queried. Output goes to stdout unless a file name is specified.\n");
				//nlist plist
				System.out.println("nlist plist -o output.dot : Iterates through the peers' plist, retrieves each peer's neighbours, and generates a graph in the Graphviz dot format. This graph is saved to the given output file.\n");
				//flist
				System.out.println("flist : lists known files (ie. local and neighbours' files), along with the associated peer.\n");
				//find
				System.out.println("find [file name] [TTL] [K]\n");
				//get
				System.out.println("get [peer Name] [file name]\n");
			} else if(curLine.startsWith("hello")) { //hello
				if(args.length == 2) { //correct number of args
					String[] ipPort = args[1].split(":");
					String ip = ipPort[0];
					int port = Integer.parseInt(ipPort[1]);
					Registry registry;
					Message rmiMessage;

					/*
					 * Send hello
					 */
					System.out.println("...");
					try {
						registry = LocateRegistry.getRegistry(ip, port); //get the “registry” 
						rmiMessage = (Message)(registry.lookup(Config.ServerName)); //look up remote object
						rmiMessage.hello(thisPeer, Config.TTL); //call remote method
						System.out.println("Discovery of other peers completed.");
					} catch(ConnectException e) {
						System.out.println("Connection refused to host: "+ip+":"+port);
					} catch (NotBoundException e) {
						e.printStackTrace();
						System.out.println("Discovery of other peers failed.");
					}
				} else {
					printHelp();
				}
			} else if(curLine.equals("plist")) { //plist
				System.out.println(peerPool.toString());
			} else if(curLine.startsWith("nlist")) { //nlist
				Dot dot = new Dot();
				List<Peer> peers = new ArrayList<Peer>();
				peers.add(thisPeer);

				if(args.length == 1) { //nlist
					//do nothing
				} else if(args.length > 2 && args[1].equals("plist")) { //nlist plist
					peers.addAll(peerPool.getPeerPoolList());

					//"-o output.txt"
					if(args[2].equals("-o")) {
						try {
							neighborList.writeToFile(dot.getDot(peers), new File(args[3]));
						} catch (NotBoundException e) {
							System.out.println("Unable to write to file");
						}
					}
				} else if(args.length > 1) { //nlist args
					boolean output = false;
					for(String pn : args) { //peer names
						//"-o output.txt"
						if(pn.equals("-o")) {
							output = true;
						} else if(output) { 
							try {
								neighborList.writeToFile(dot.getDot(peers), new File(pn));
							} catch (NotBoundException e) {
								System.out.println("Unable to write to file");
							}
						}

						Peer peer = peerPool.getPeerFromName(pn);
						if(peer==null) {
							//do nothing
						} else {
							peers.add(peer);
						}
					}
				}

				try {
					System.out.println(dot.getDot(peers));
				} catch (NotBoundException e) {
					System.out.println("Unable to generate network");
				}
			} else if(curLine.equals("flist")){
				System.out.println(fileList.toString());
			}else if(curLine.startsWith("find")){
				if(!(args.length == 4)){
					System.out.println("unknown find command!! use: find [file name] [TTL] [K]");
				}else{
					String fileName = args[1];
					int TTL = 0, K = 0;
					try{
						TTL = Integer.parseInt(args[2]);
						K = Integer.parseInt(args[3]);
						if( TTL < 0 || K < 0 ) throw new NumberFormatException();
					}catch(NumberFormatException e){
						System.out.println("[TTL] and [K] parameter has to be a positiv integer number");
					}
					k.doKwalker(fileName, TTL, K, null, null, null);
				}
			}else if(curLine.startsWith("get")){
				if(!(args.length == 3)){
					System.out.println("unknown get command!! use: get [peer Name] [file name]");
				}else{
					Peer peer = peerPool.getPeerFromName(args[1]);
					if(peer == null){
						System.out.println("unknown peer name: "+ args[1]);
					}else{
						Registry registry;
						Message rmiServer;
						try {
							registry = LocateRegistry.getRegistry(peer.getIp(), peer.getPort()); //get the “registry” 
							rmiServer = (Message)registry.lookup(Config.ServerName); //look up remote object
							k.fileDownload(rmiServer.fileUpload(args[2]), args[2]);
						} catch (NotBoundException e) {
							e.printStackTrace();
						} 
					}
				}
			}else if(curLine.startsWith("test")){
				int TTL = Integer.parseInt(args[1]);
				int K = Integer.parseInt(args[2]);
				k.doKwalker("P2PN.xml", TTL, K, null, null, null);
			}else if(curLine.startsWith("graf")){
				Dot dot = new Dot();
				List<Peer> peers = new ArrayList<Peer>();
				peers.add(thisPeer);
				peers.addAll(peerPool.getPeerPoolList());
				try {
					neighborList.writeToFile(dot.getDot(peers), new File("graf.dot"));
				} catch (NotBoundException e) {
					e.printStackTrace();
				}
			}else if(curLine.equals("quit")) { //quit
				running=false;
				s.quit();
				System.exit(0);
			}else{
				printHelp();
			}
		}//Get neighborlist for peer p

	}

	private void printHelp() {
		System.out.println("Unknown command, type 'help' for help.");
	}
}
